package cn.zhouyafeng.itchat4j.core;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Pair;
import cn.zhouyafeng.itchat4j.Wechat;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import cn.zhouyafeng.itchat4j.beans.BaseMsg;
import cn.zhouyafeng.itchat4j.utils.MyHttpClient;
import cn.zhouyafeng.itchat4j.utils.enums.parameters.BaseParaEnum;
import org.apache.http.client.CookieStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 核心存储类，全局只保存一份，单例模式
 * @author https://github.com/yaphone
 * @version 1.0
 * @date 创建时间：2017年4月23日 下午2:33:56
 */
public class Core implements Serializable {
    private final static Logger logger = LoggerFactory.getLogger(Core.class);
    private static final long serialVersionUID = 1L;
    private static String hotReloadDir = Wechat.getRootDir() + "backup";
    private final ExecutorService threadPool = Executors.newCachedThreadPool();
    private volatile boolean alive = false;
    private Map<String, Object> loginInfo = new HashMap<>();
    private MyHttpClient myHttpClient = new MyHttpClient();
    private String uuid = null;
    private boolean useHotReload = true;
    private int receivingRetryCount = 5;
    private int memberCount = 0;
    private String indexUrl;
    private String userName;
    private String nickName;
    private BlockingQueue<BaseMsg> msgList = CollUtil.newBlockingQueue(100, false);
    private JSONObject userSelf; // 登陆账号自身信息
    private List<JSONObject> memberList = new ArrayList<JSONObject>(); // 好友+群聊+公众号+特殊账号
    private List<JSONObject> contactList = new ArrayList<JSONObject>();// 好友
    private List<JSONObject> groupList = new ArrayList<JSONObject>();
    // 群
    private Map<String, JSONArray> groupMemeberMap = new HashMap<String, JSONArray>(); // 群聊成员字典
    private List<JSONObject> publicUsersList = new ArrayList<JSONObject>();
    // 公众号／服务号
    private List<JSONObject> specialUsersList = new ArrayList<JSONObject>();
    // 特殊账号
    private List<String> groupIdList = new ArrayList<String>(); // 群ID列表
    private List<String> groupNickNameList = new ArrayList<String>(); // 群NickName列表
    private Map<String, JSONObject> userInfoMap = new HashMap<String, JSONObject>();
    private long lastNormalRetcodeTime; // 最后一次收到正常retcode的时间，秒为单位

    private Core() {
    }

    public static Core newInstance(boolean useHotReload) {
        Core core = new Core();
        if (core.useHotReload = useHotReload) {
            Pair<CookieStore, Map<String, Object>> pair = loadLoginState();
            if (pair != null) {
                core.setMyHttpClient(new MyHttpClient(pair.getKey()));
                core.setLoginInfo(pair.getValue());
                core.setAlive(true);
                logger.info("加载cookie成功!");
            }
        }
        return core;
    }

    private static synchronized Pair<CookieStore, Map<String, Object>> loadLoginState() {
        ObjectInputStream ois = null;
        File file = new File(Core.hotReloadDir);
        try {
            ois = new ObjectInputStream(new FileInputStream(file));
            Pair<CookieStore, Map<String, Object>> pair = (Pair<CookieStore, Map<String, Object>>) ois.readObject();
            return pair;
        } catch (Exception e) {
            if (file.exists()) {
                file.delete();
            }
            e.printStackTrace();
        } finally {
            IoUtil.close(ois);
        }
        return null;
    }

    public static void delhotReloadDir() {
        File file = new File(Core.hotReloadDir);
        if (file.exists()) {
            file.delete();
        }
    }


    public static String getHotReloadDir() {
        return hotReloadDir;
    }

    public static void setHotReloadDir(String hotReloadDir) {
        Core.hotReloadDir = hotReloadDir;
    }

    public void shutdown() {
        logger.info("Core.shutdown() execute.    ");
        this.threadPool.shutdownNow();
        Wechat.getCroes().remove(this);
    }

    /**
     * 请求参数
     */
    public Map<String, Object> getParamMap() {
        return new HashMap<String, Object>(1) {
            private static final long serialVersionUID = 1L;

            {
                Map<String, String> map = new HashMap<String, String>();
                for (BaseParaEnum baseRequest : BaseParaEnum.values()) {
                    map.put(baseRequest.para(), getLoginInfo().get(baseRequest.value()).toString());
                }
                put("BaseRequest", map);
            }
        };
    }

    public synchronized void saveLoginState() {
        ObjectOutputStream objectOutputStream = null;
        try {
            File file = new File(Core.hotReloadDir);
            if (!file.exists()) {
                file.createNewFile();
            }
            CookieStore cookieStore = this.getMyHttpClient().getCookieStore();
            Pair<CookieStore, Map<String, Object>> pair = new Pair<>(cookieStore,getLoginInfo());
            objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
            objectOutputStream.writeObject(pair);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IoUtil.close(objectOutputStream);
        }
    }

    public boolean isAlive() {
        return alive;
    }

    public void setAlive(boolean alive) {
        this.alive = alive;
    }

    public List<JSONObject> getMemberList() {
        return memberList;
    }

    public void setMemberList(List<JSONObject> memberList) {
        this.memberList = memberList;
    }

    public Map<String, Object> getLoginInfo() {
        return loginInfo;
    }

    public void setLoginInfo(Map<String, Object> loginInfo) {
        this.loginInfo = loginInfo;
    }

    public String getUuid() {
        return uuid;
    }

    public void setUuid(String uuid) {
        this.uuid = uuid;
    }

    public int getMemberCount() {
        return memberCount;
    }

    public void setMemberCount(int memberCount) {
        this.memberCount = memberCount;
    }

    public boolean isUseHotReload() {
        return useHotReload;
    }

    public void setUseHotReload(boolean useHotReload) {
        this.useHotReload = useHotReload;
    }

    public int getReceivingRetryCount() {
        return receivingRetryCount;
    }

    public void setReceivingRetryCount(int receivingRetryCount) {
        this.receivingRetryCount = receivingRetryCount;
    }

    public MyHttpClient getMyHttpClient() {
        return myHttpClient;
    }

    public void setMyHttpClient(MyHttpClient myHttpClient) {
        this.myHttpClient = myHttpClient;
    }

    public BlockingQueue<BaseMsg> getMsgList() {
        return msgList;
    }

    public void setMsgList(BlockingQueue<BaseMsg> msgList) {
        this.msgList = msgList;
    }

    public List<String> getGroupIdList() {
        return groupIdList;
    }

    public void setGroupIdList(List<String> groupIdList) {
        this.groupIdList = groupIdList;
    }

    public List<JSONObject> getContactList() {
        return contactList;
    }

    public void setContactList(List<JSONObject> contactList) {
        this.contactList = contactList;
    }

    public List<JSONObject> getGroupList() {
        return groupList;
    }

    public void setGroupList(List<JSONObject> groupList) {
        this.groupList = groupList;
    }

    public List<JSONObject> getPublicUsersList() {
        return publicUsersList;
    }

    public void setPublicUsersList(List<JSONObject> publicUsersList) {
        this.publicUsersList = publicUsersList;
    }

    public List<JSONObject> getSpecialUsersList() {
        return specialUsersList;
    }

    public void setSpecialUsersList(List<JSONObject> specialUsersList) {
        this.specialUsersList = specialUsersList;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public JSONObject getUserSelf() {
        return userSelf;
    }

    public void setUserSelf(JSONObject userSelf) {
        this.userSelf = userSelf;
    }

    public Map<String, JSONObject> getUserInfoMap() {
        return userInfoMap;
    }

    public void setUserInfoMap(Map<String, JSONObject> userInfoMap) {
        this.userInfoMap = userInfoMap;
    }

    public synchronized long getLastNormalRetcodeTime() {
        return lastNormalRetcodeTime;
    }

    public synchronized void setLastNormalRetcodeTime(long lastNormalRetcodeTime) {
        this.lastNormalRetcodeTime = lastNormalRetcodeTime;
    }

    public List<String> getGroupNickNameList() {
        return groupNickNameList;
    }

    public void setGroupNickNameList(List<String> groupNickNameList) {
        this.groupNickNameList = groupNickNameList;
    }

    public Map<String, JSONArray> getGroupMemeberMap() {
        return groupMemeberMap;
    }

    public void setGroupMemeberMap(Map<String, JSONArray> groupMemeberMap) {
        this.groupMemeberMap = groupMemeberMap;
    }

    public String getIndexUrl() {
        return indexUrl;
    }

    public void setIndexUrl(String indexUrl) {
        this.indexUrl = indexUrl;
    }

    public ExecutorService getThreadPool() {
        return threadPool;
    }
}
